PageHelper分页后,分页参数丢失问题

您所在的位置:网站首页 pagehelper 物理分页 PageHelper分页后,分页参数丢失问题

PageHelper分页后,分页参数丢失问题

#PageHelper分页后,分页参数丢失问题| 来源: 网络整理| 查看: 265

大多数系统都需要分析功能。通常都是用物理分页实现,比如我们用关系数据库时是使用 SQL 语句提供的分页参数实现(比如 MySQL 的 limit 参数)。但在不同的关系数据库中,SQL 语句的分页参数都不同,所以有一些框架会提供通用的分页功能,屏蔽不同数据库的分页方式。在使用 MyBatis 操作数据库的 WEB 系统中,我们可以使用 PageHelper 插件轻松实现支持各种数据库的分页功能。关于该插件的介绍和使用请前往 GitHub地址:github.com/pagehelper/… 。

目前经手的项目中,分页功能都是使用了 PageHelper 插件。调试 PageHelper 源码可以知道它是基于 MyBatis 的拦截器功能扩展实现的。不过这篇文章想说的是项目中遇到的一个使用 PageHelper 的小问题,这里记录下。

问题代码

@GetMapping("/users") public PageInfo listUsers(@RequestParam int pageNum, @RequestParam int pageSize, @RequestParam String user, @RequestParam String phone) { // 开启分页 PageHelper.startPage(pageNum, pageSize); // 多条件查询用户信息列表 List users = userService.list(user, phone); // 处理users,返回需要的信息 List userDTOs = convertUser(users); // 包装users,返回分页和数据信息 return new PageInfo(userDTOs);} /** * 返回users中需要的信息,其他字段不返回 */ public List convertUser(List users) { List userDTOs = new ArrayList(); if(users != null && !users.isEmpty()) { users.foreach(user -> { UserDTO userDTO = new UserDTO(); userDTO.setUserName(user.getUserName); userDTO.setPhone(user.getPhone); userDTOs.add(userDTO); }); } return userDTOs; }复制代码

注意:想要开启分页,必须使用 PageHelper.startPage(pageNum, pageSize); 而且使用该语句后,仅仅对其后的第一条查询语句产生分页效果。

查询结果

利用 PostMan 查询该接口,返回信息如下截图:

pageNum=1&pageSize=1 时的查询结果

pageNum=1&pageSize=10 时的查询结果

上面两次查询,图 1 的结果中分页参数是有问题的。比如总条数 count 和当前条数 currentCount 相同,总页数 pages 是 1。这明显是不对的。正确的结果应该是:图 1 的 count = 3, currentCount = 1, pages = 2;

分析users的真实类型

问题代码中的查询语句:List users = userService.list(userName, phone); 返回值 users 其实并不是 ArrayList 的实例,因为开启了分页,所以 users是 PageHelper 插件中的 Page 类的实例。所以返回值可以用Page接受(注意:不能用PageInfo接收)

Page users = userService.list(user, phone); 返回值可以用Page接收复制代码

PageHelper 插件的原理是通过 MyBatis 的拦截器机制实现的,以下是 PageHelper 的拦截器的分页查询逻辑:

runtimeDialect.afterPage(resultList, parameterObject, rowBounds); 代码如下:

图中执行分页查询 executor.query(......) 后的结果 resultList 会被放到 page 对象中,即 page.addAll(pageList); PageHelper 中的类 Page 是继承 ArrayList 类。最后这个 page 会被赋值给代码中的 users 引用(通过 Object 做强制类型转换)。

错误原因分析

上面分析了 users 的真实类型是 Page 类的实例。所以当调用了 convertUsers(users) 方法后会丢失分页相关的参数信息,返回值 userDTOs 已经不是 Page 的实例了,userDTOs 只是普通的 ArrayList 实例,没有分页相关的参数信息,比如 count, pages 等。执行 new PageInfo(userDTOs) 时的源码如下:

即 userDTOs 是 Collection 子类实例,所以执行了红框中的逻辑,也就导致了我们上面两次查询中错误结果。

解决办法

新建一个 PageInfo 对象,将分页参数和需要重新构建的数据设置到新的 PageInfo 中即可。代码如下:

@GetMapping("/users") public PageInfo listUsers(@RequestParam int pageNum, @RequestParam int pageSize, @RequestParam String user, @RequestParam String phone) { // 开启分页 PageHelper.startPage(pageNum, pageSize); // 多条件查询用户信息列表 List users = userService.list(user, phone); PageInfo userDTOPageInfo = PageInfoUtil.pageInfo2PageInfo(new PageInfo(users)); // 处理users,设置给userDTOPageInfo convertUser(users, userDTOPageInfo); // 包装users,返回分页和数据信息 return userDTOPageInfo;} /** * 返回users中需要的信息,其他字段不返回 */ public List convertUser(List users, PageInfo userDTOPageInfo) { List userDTOs = new ArrayList(); if(users != null && !users.isEmpty()) { users.foreach(user -> { UserDTO userDTO = new UserDTO(); userDTO.setUserName(user.getUserName); userDTO.setPhone(user.getPhone); // 将新建的数据放入 userDTOPageInfo 中 userDTOPageInfo.getList().add(userDTO); }); } return userDTOPageInfo;} 复制代码

public class PageInfoUtil { /** * pageInfo对象转换的泛型方法 * P :入参类型 V:出参类型 */ public static PageInfo PageInfo2PageInfoVo(PageInfo pageInfoPo) { // 创建Page对象,实际上是一个ArrayList类型的集合 Page page = new Page(pageInfoPo.getPageNum(), pageInfoPo.getPageSize()); // 设置总记录数 page.setTotal(pageInfoPo.getTotal()); // 创建 PageInfo 对象 PageInfo pageInfo = new PageInfo(page); // 设置当前记录总数 pageInfo.setSize(pageInfoPo.getList().size()); return pageInfo; } }复制代码

历史文章

谈谈 MyBatis 的插件化设计

 MyBatis 的插件对象如何创建出来的

自定义 MyBatis 拦截器,为业务赋能



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3